/**
 * 音频工具函数
 */

/**
 * Base64 转 Blob
 * @param base64 - base64编码的音频数据
 * @param mimeType - MIME类型，默认为 audio/mp3
 * @returns Blob对象
 */
export const base64ToBlob = (base64: string, mimeType: string = 'audio/mp3'): Blob => {
  // 检查 base64 格式
  if (!base64.startsWith('data:audio/')) {
    // 如果不是完整的 data URL，添加前缀
    base64 = `data:${mimeType};base64,${base64}`
  } else {
    // 如果已经是完整的 data URL，提取实际的 MIME 类型
    const match = base64.match(/^data:(audio\/[^;]+);base64,/)
    if (match) {
      mimeType = match[1]
    }
  }

  try {
    const byteCharacters = atob(base64.split(',')[1])
    const byteArrays = []

    for (let offset = 0; offset < byteCharacters.length; offset += 512) {
      const slice = byteCharacters.slice(offset, offset + 512)
      const byteNumbers = new Array(slice.length)

      for (let i = 0; i < slice.length; i++) {
        byteNumbers[i] = slice.charCodeAt(i)
      }

      const byteArray = new Uint8Array(byteNumbers)
      byteArrays.push(byteArray)
    }

    return new Blob(byteArrays, { type: mimeType })
  } catch (error) {
    console.error('Base64 转换失败:', error)
    throw new Error('音频数据格式错误')
  }
}

/**
 * 创建音频元素并加载音频
 * @param audioUrl - 音频URL
 * @param options - 配置选项
 * @returns Promise<HTMLAudioElement>
 */
export const createAudioElement = async (
  audioUrl: string,
  options: {
    preload?: 'none' | 'metadata' | 'auto'
    crossOrigin?: string
    timeout?: number
  } = {},
): Promise<HTMLAudioElement> => {
  const { preload = 'auto', crossOrigin = 'anonymous', timeout = 10000 } = options

  return new Promise((resolve, reject) => {
    const audio = new Audio()
    audio.preload = preload
    audio.crossOrigin = crossOrigin
    audio.src = audioUrl

    const handleCanPlay = () => {
      console.log('[createAudioElement] canplay事件触发', {
        readyState: audio.readyState,
        duration: audio.duration, // 此时duration可能已可用
      })
      audio.removeEventListener('loadedmetadata', handleLoadedmetadata)
      audio.removeEventListener('canplay', handleCanPlay)
      audio.removeEventListener('error', handleError)
      clearTimeout(timeoutId)
      resolve(audio)
    }

    const handleError = (e: Event) => {
      const audioElement = e.target as HTMLAudioElement
      console.error('[createAudioElement] error事件触发', {
        error: audioElement.error?.message,
        errorCode: audioElement.error?.code, // 错误码（如MEDIA_ERR_DECODE）
        src: audioElement.src,
      })
      audio.removeEventListener('loadedmetadata', handleLoadedmetadata)
      audio.removeEventListener('canplay', handleCanPlay)
      audio.removeEventListener('error', handleError)
      clearTimeout(timeoutId)
      console.error('音频加载错误:', e)
      reject(new Error('音频加载失败'))
    }

    const handleLoadedmetadata = (e: Event) => {
      console.log('[createAudioElement] Loadedmetadata事件触发', {
        readyState: audio.readyState,
        duration: audio.duration, // 此时duration可能已可用
      })
    }

    const timeoutId = setTimeout(() => {
      console.error('[createAudioElement] 超时（' + timeout + 'ms）', {
        src: audio.src,
        preload: audio.preload,
        readyState: audio.readyState,
      })
      audio.removeEventListener('canplay', handleCanPlay)
      audio.removeEventListener('error', handleError)
      reject(new Error('音频加载超时'))
    }, timeout)

    audio.addEventListener('loadedmetadata', handleLoadedmetadata)
    audio.addEventListener('canplay', handleCanPlay)
    audio.addEventListener('error', handleError)
    console.log('[createAudioElement] 已添加loadedmetadata/canplay/error事件监听')
  })
}

/**
 * 播放音频
 * @param audio - 音频元素
 * @returns Promise<void>
 */
export const playAudio = async (audio: HTMLAudioElement): Promise<void> => {
  try {
    await audio.play()
  } catch (error) {
    console.error('音频播放失败:', error)
    throw new Error('音频播放失败')
  }
}

/**
 * 停止音频
 * @param audio - 音频元素
 */
export const stopAudio = (audio: HTMLAudioElement): void => {
  if (audio) {
    audio.pause()
    audio.currentTime = 0
  }
}

/**
 * 清理音频资源
 * @param audio - 音频元素
 * @param blobUrl - Blob URL（如果有）
 */
export const cleanupAudio = (audio: HTMLAudioElement | null, blobUrl?: string): void => {
  if (audio) {
    audio.pause()
    audio.src = ''
    audio.load()
  }

  if (blobUrl) {
    URL.revokeObjectURL(blobUrl)
  }
}

/**
 * 检查音频是否支持
 * @returns boolean
 */
export const isAudioSupported = (): boolean => {
  return typeof Audio !== 'undefined' && typeof HTMLAudioElement !== 'undefined'
}

/**
 * 获取音频格式支持情况
 * @returns 支持的格式对象
 */
export const getAudioFormatSupport = (): Record<string, boolean> => {
  const audio = new Audio()
  return {
    mp3: audio.canPlayType('audio/mpeg') !== '',
    wav: audio.canPlayType('audio/wav') !== '',
    ogg: audio.canPlayType('audio/ogg') !== '',
    aac: audio.canPlayType('audio/aac') !== '',
    webm: audio.canPlayType('audio/webm') !== '',
  }
}
// 验证音频有效性
export const verifyAudio = (blob: Blob): Promise<void> => {
  return new Promise((resolve, reject) => {
    const testAudio = new Audio()
    testAudio.src = URL.createObjectURL(blob)

    testAudio.addEventListener('loadedmetadata', () => {
      URL.revokeObjectURL(testAudio.src)
      resolve()
    })

    testAudio.addEventListener('error', (e) => {
      URL.revokeObjectURL(testAudio.src)
      reject(new Error(`音频验证失败: ${e.message}`))
    })

    // 设置更短的验证超时
    setTimeout(() => {
      reject(new Error('音频验证超时'))
    }, 3000)
  })
}
